#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "timers.h"
#include "mpi.h"

double calcEX(double x);
double calcField(double start, double stop, double h);
long int recTimer();


main(int argc, char **argv)
{
	int n = 1024;
			
			if(argc>1) {
				n = (int) strtol(argv[1], NULL, 10);

			}
	
	long int time_start = recTimer();
	int np, rank;
	MPI_Status status;

	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	MPI_Comm_size(MPI_COMM_WORLD, &np);

	int a,b;
	a = -2;
	b = 2;
	

	int roundup = n%np;

	double totalField = 0;

	int i,j;
	double start_a, stop_b;
	double jump = 4;
	jump = jump/n;
	double offset = (n - roundup)/np;
	 long int process_time = recTimer();
	
	for(i=0; i<offset; i++) {
		start_a = -2 + (double)(jump * (offset*rank)) + (jump * i);
		stop_b = start_a + jump;
		totalField = totalField + calcField(start_a, stop_b, jump);


	}

	if(rank==(np-1)) {
		for(j=0;j<roundup; j++) {
			start_a = -2 + jump * ((offset)*(rank+1)) + (j * jump);
			stop_b = start_a + jump;
			totalField = totalField + calcField(start_a, stop_b, jump);

		}

	}
	printf("Proces (%d): %0.8f s \n", rank, (double)(recTimer() - process_time)/1000000000);
	
	double wynik = 0;
	MPI_Reduce(&totalField, &wynik, 1, MPI_DOUBLE,MPI_SUM, 0, MPI_COMM_WORLD);

	if(rank == 0) {
		printf("%0.10f \n", wynik);
	}
	MPI_Finalize();
	
	if(rank==0) {
	        	
	        	printf("Czas całego programu: %f \n", (double)(recTimer()-time_start) / 1000000000);
	        }
}

double calcEX(double x) {

	return pow(M_E, -pow(x, 2));

}

double calcField(double start, double stop, double h) {

	return ((calcEX(start) + calcEX(stop)) * h) / 2;

}
long int recTimer() {
	struct timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
	return ((t.tv_sec * TIMER_SCALE) + t.tv_nsec);
}
